#pragma once


#include <cmath>


class Vector
{
public:
    Vector() : _x(0.0f), _y(0.0f), _z(0.0f) { }
    Vector(double x1, double y1, double z1) : _x(x1), _y(y1), _z(z1) { }
    Vector(const Vector& v) : _x(v._x), _y(v._y), _z(v._z) { }

    double x() const { return _x; }
    double y() const { return _y; }
    double z() const { return _z; }

    Vector& operator=(const Vector& v)
    {
        _x = v._x;
        _y = v._y;
        _z = v._z;
        return *this;
    }

    Vector& operator+=(const Vector& v)
    {
        _x += v._x;
        _y += v._y;
        _z += v._z;
        return *this;
    }

    Vector& operator-=(const Vector& v)
    {
        _x -= v._x;
        _y -= v._y;
        _z -= v._z;
        return *this;
    }

    Vector& operator*=(double c)
    {
        _x *= c;
        _y *= c;
        _z *= c;
        return *this;
    }

    Vector operator-() const
    {
        return Vector(-_x, -_y, -_z);
    }

    Vector operator+(const Vector& v) const
    {
        return Vector(_x + v._x, _y + v._y, _z + v._z);
    }

    Vector operator-(const Vector& v) const
    {
        return Vector(_x - v._x, _y - v._y, _z - v._z);
    }

    Vector operator*(double c) const
    {
        return Vector(_x * c, _y * c, _z * c);
    }

    double dot(const Vector& v) const
    {
        return _x * v._x + _y * v._y + _z * v._z;
    }

    Vector cross(const Vector& v) const
    {
        return Vector(
            _y * v._z - _z * v._y,
            _z * v._x - _x * v._z,
            _x * v._y - _y * v._x
        );
    }

    double length() const
    {
        return static_cast<double>(sqrt(static_cast<double>(length2())));
    }

    double length2() const
    {
        return _x * _x + _y * _y + _z * _z;
    }

    void normalize()
    {
        double len = length();
        _x /= len;
        _y /= len;
        _z /= len;
    }

    Vector getNormalized() const
    {
        double len = length();
        return Vector (
            _x / len,
            _y / len,
            _z / len
        );
    }

    Vector getUnitVector() const
    {
        Vector v(*this);
        v *= 1.0f / v.length();
        return v;
    }

private:
    double _x;
    double _y;
    double _z;
};
